﻿using System;
using NeuralLib.ActivationFunction;

namespace NeuralLib
{
    [Serializable]
    public class Neuron
    {
        protected static Random _rand = new Random();
        protected IActivationFunction _function = null;
        protected int _inputsCount = 0;
        protected double _output = 0;

        protected double _threshold = 0;

        protected double[] _weights = null;

        public Neuron(int inputs, IActivationFunction function)
        {
            _function = function;
            _inputsCount = Math.Max(1, inputs);
            _weights = new double[_inputsCount];

            SetInitialWeights();
        }

        public static Random Random
        {
            get { return _rand; }
            set
            {
                if (value != null)
                {
                    _rand = value;
                }
            }
        }

        public IActivationFunction ActivationFunction
        {
            get { return _function; }
            set { _function = value; }
        }

        public int InputsCount
        {
            get { return _inputsCount; }
        }

        public double Output
        {
            get { return _output; }
        }

        public double Threshold
        {
            get { return _threshold; }
            set { _threshold = value; }
        }

        public double[] Weights
        {
            get { return _weights; }
        }

        public double Compute(double[] input)
        {
            if (input.Length != _inputsCount)
                throw new ArgumentException("Wrong length of the input vector.");

            var sum = 0.0;

            for (var i = 0; i < _inputsCount; i++)
            {
                sum += _weights[i] * input[i];
            }
            sum += _threshold;

            var output = _function.Function(sum);

            _output = output;

            return output;
        }

        public void SetInitialWeights()
        {
            for (var i = 0; i < _inputsCount; i++)
                _weights[i] = _rand.NextDouble() - _rand.NextDouble();

            _threshold = _rand.NextDouble() - _rand.NextDouble();
        }
    }
}